<?php
// 引入数据库配置
require 'config.php';

// 设置响应头为JSON格式
header('Content-Type: application/json');

/**
 * 改进的图片上传类，不依赖Imagick和GD扩展
 */
class ImageUploader {
    private $pdo;
    private $uploadDir;
    private $validTypes;
    private $maxSize;

    /**
     * 构造函数
     * @param PDO $pdo 数据库连接对象
     */
    public function __construct($pdo) {
        $this->pdo = $pdo;
        // 使用绝对路径
        $this->uploadDir = realpath(__DIR__) . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
        $this->validTypes = ['image/jpeg', 'image/png', 'image/bmp', 'image/webp', 'image/gif'];
        $this->maxSize = 5 * 1024 * 1024; // 5MB

        // 记录初始化信息
        error_log('ImageUploader initialized without GD and Imagick extensions');
    }

    /**
     * 检查并创建上传目录
     * @throws Exception 当目录无法创建或不可写时抛出
     */
    private function checkUploadDir() {
        if (!is_dir($this->uploadDir)) {
            // 创建目录
            if (!mkdir($this->uploadDir, 0755, true)) {
                throw new Exception('无法创建上传目录: ' . $this->uploadDir);
            }
        }

        if (!is_writable($this->uploadDir)) {
            throw new Exception('上传目录不可写: ' . $this->uploadDir);
        }

        // 创建.htaccess文件防止目录浏览
        $htaccessPath = $this->uploadDir . '.htaccess';
        if (!file_exists($htaccessPath)) {
            $htaccessContent = 'Options -Indexes
Deny from all
<FilesMatch \.(jpg|jpeg|png|gif|webp|bmp)$>
    Allow from all
</FilesMatch>';
            file_put_contents($htaccessPath, $htaccessContent);
        }
    }

    /**
     * 验证文件
     * @param array $file 上传的文件信息
     * @return array 错误信息数组，为空表示验证通过
     */
    private function validateFile($file) {
        $errors = [];

        // 检查文件错误
        if ($file['error'] !== UPLOAD_ERR_OK) {
            switch ($file['error']) {
                case UPLOAD_ERR_INI_SIZE:
                case UPLOAD_ERR_FORM_SIZE:
                    $errors[] = '文件超过大小限制';
                    break;
                case UPLOAD_ERR_PARTIAL:
                    $errors[] = '文件仅部分上传';
                    break;
                case UPLOAD_ERR_NO_FILE:
                    $errors[] = '没有文件被上传';
                    break;
                case UPLOAD_ERR_NO_TMP_DIR:
                    $errors[] = '缺少临时文件夹';
                    break;
                case UPLOAD_ERR_CANT_WRITE:
                    $errors[] = '文件写入失败';
                    break;
                case UPLOAD_ERR_EXTENSION:
                    $errors[] = '文件上传被PHP扩展阻止';
                    break;
                default:
                    $errors[] = '文件上传错误: 错误码 ' . $file['error'];
            }
            return $errors;
        }

        // 验证文件类型 (MIME类型检查)
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mime = finfo_file($finfo, $file['tmp_name']);
        finfo_close($finfo);

        if (!in_array($mime, $this->validTypes)) {
            $errors[] = '文件类型不支持，请上传JPG、PNG、BMP、WebP或GIF格式的图片';
            return $errors;
        }

        // 验证文件大小
        if ($file['size'] > $this->maxSize) {
            $errors[] = '文件超过5MB大小限制';
        }

        // 检查文件名是否包含恶意路径
        $fileName = basename($file['name']);
        if ($fileName !== $file['name']) {
            $errors[] = '文件名无效，可能包含路径遍历字符';
        }

        // 验证文件扩展名
        $extension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
        $validExtensions = ['jpg', 'jpeg', 'png', 'bmp', 'webp', 'gif'];
        if (!in_array($extension, $validExtensions)) {
            $errors[] = '文件扩展名不支持，请上传JPG、PNG、BMP、WebP或GIF格式的图片';
        }

        return $errors;
    }

    /**
     * 生成唯一文件名
     * @param string $fileName 原始文件名
     * @return string 唯一文件名
     */
    private function generateUniqueName($fileName) {
        $extension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
        // 确保扩展名有效
        $validExtensions = ['jpg', 'jpeg', 'png', 'bmp', 'webp', 'gif'];
        if (!in_array($extension, $validExtensions)) {
            $extension = 'jpg'; // 默认使用jpg
        }
        // 使用更安全的方式生成唯一文件名
        return bin2hex(random_bytes(16)) . '.' . $extension;
    }

    /**
     * 上传到本地服务器
     * @param array $file 上传的文件信息
     * @return string 上传后的文件路径
     * @throws Exception 当上传失败时抛出
     */
    private function uploadToLocal($file) {
        $uniqueName = $this->generateUniqueName($file['name']);
        $uploadPath = $this->uploadDir . $uniqueName;

        // 使用更安全的方式移动文件
        if (!move_uploaded_file($file['tmp_name'], $uploadPath)) {
            // 尝试备用方法
            if (!copy($file['tmp_name'], $uploadPath)) {
                throw new Exception('文件移动失败: ' . $file['name']);
            }
            unlink($file['tmp_name']); // 删除临时文件
        }

        // 设置文件权限
        chmod($uploadPath, 0644);

        // 返回相对路径
        return 'uploads/' . $uniqueName;
    }

    /**
     * 处理上传
     * @param int $ticketId 工单ID
     * @param array $files 上传的文件数组
     * @return array 处理结果
     */
    public function processUpload($ticketId, $files) {
        try {
            // 检查工单ID
            if (empty($ticketId) || !is_numeric($ticketId)) {
                throw new Exception('无效的工单ID');
            }

            // 检查是否有文件上传
            if (empty($files['name'][0])) {
                throw new Exception('请选择要上传的图片');
            }

            // 检查上传目录
            $this->checkUploadDir();

            $uploadedImages = [];
            $errors = [];

            // 开始数据库事务
            $this->pdo->beginTransaction();

            try {
                // 处理每个文件
                for ($i = 0; $i < count($files['tmp_name']); $i++) {
                    $file = [
                        'name' => $files['name'][$i],
                        'type' => $files['type'][$i],
                        'tmp_name' => $files['tmp_name'][$i],
                        'error' => $files['error'][$i],
                        'size' => $files['size'][$i]
                    ];

                    // 验证文件
                    $fileErrors = $this->validateFile($file);
                    if (!empty($fileErrors)) {
                        $errors[] = '文件 ' . $file['name'] . ' 上传失败: ' . implode(', ', $fileErrors);
                        continue;
                    }

                    try {
                        // 上传文件
                        $imagePath = $this->uploadToLocal($file);
                        $uploadedImages[] = $imagePath;
                    } catch (Exception $e) {
                        $errors[] = '文件 ' . $file['name'] . ' 上传失败: ' . $e->getMessage();
                    }
                }

                // 更新工单的图片信息
                if (!empty($uploadedImages)) {
                    // 先获取现有的图片
                    $sql = "SELECT screenshots FROM tickets WHERE id = :id FOR UPDATE";
                    $stmt = $this->pdo->prepare($sql);
                    $stmt->bindParam(':id', $ticketId, PDO::PARAM_INT);
                    $stmt->execute();
                    $existingImages = $stmt->fetchColumn();

                    // 合并现有图片和新上传的图片
                    $allImages = [];
                    if (!empty($existingImages)) {
                        $allImages = explode(',', $existingImages);
                    }
                    $allImages = array_merge($allImages, $uploadedImages);

                    // 更新数据库
                    $sql = "UPDATE tickets SET screenshots = :screenshots WHERE id = :id";
                    $stmt = $this->pdo->prepare($sql);
                    $stmt->bindParam(':screenshots', implode(',', $allImages));
                    $stmt->bindParam(':id', $ticketId, PDO::PARAM_INT);
                    $stmt->execute();
                }

                // 提交事务
                $this->pdo->commit();

            } catch (Exception $e) {
                // 回滚事务
                $this->pdo->rollBack();
                throw $e;
            }

            return [
                'success' => empty($errors),
                'message' => empty($errors) ? '图片上传成功，共上传 ' . count($uploadedImages) . ' 张图片' : $errors,
                'uploaded_images' => count($uploadedImages)
            ];
        } catch (Exception $e) {
            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }
}

// 处理请求
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    try {
        // 检查是否有数据库连接
        if (!isset($pdo) || !$pdo instanceof PDO) {
            throw new Exception('数据库连接未初始化');
        }

        $uploader = new ImageUploader($pdo);
        $result = $uploader->processUpload(
            $_POST['ticket_id'] ?? '',
            $_FILES['screenshots'] ?? []
        );

        echo json_encode($result);
    } catch (Exception $e) {
        echo json_encode([
            'success' => false,
            'message' => $e->getMessage()
        ]);
    }
} else {
    echo json_encode([
        'success' => false,
        'message' => '请求方法错误，只支持POST请求'
    ]);
}
?>